﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using CNFM_CROCODILE_LOGO.Data.DBContext;
using CNFM_CROCODILE_LOGO.OAuth.OAuth;
using CNFM_CROCODILE_LOGO_WebApi.OAuthManagement;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using Swashbuckle.AspNetCore.Swagger;

namespace CNFM_CROCODILE_LOGO_WebApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });


            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            #region Jwt 
            //添加策略鉴权模式
            services.AddAuthorization(options =>
            {
                options.AddPolicy("Permission", policy => policy.Requirements.Add(new PolicyRequirement()));
            })
            .AddAuthentication(s =>
            {
                //添加JWT Scheme
                s.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                s.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
                s.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            //添加jwt验证：
            .AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateLifetime = true,//是否验证失效时间
                    ClockSkew = TimeSpan.FromSeconds(30),

                    ValidateAudience = true,//是否验证Audience
                    //ValidAudience = Const.GetValidudience(),//Audience
                    //这里采用动态验证的方式，在重新登陆时，刷新token，旧token就强制失效了
                    AudienceValidator = (m, n, z) =>
                    {
                        return m != null && m.FirstOrDefault().Equals(Const.ValidAudience);
                    },
                    ValidateIssuer = true,//是否验证Issuer
                    ValidIssuer = Const.Domain,//Issuer，这两项和前面签发jwt的设置一致

                    ValidateIssuerSigningKey = true,//是否验证SecurityKey
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Const.SecurityKey))//拿到SecurityKey
                };
                options.Events = new JwtBearerEvents
                {
                    OnAuthenticationFailed = context =>
                    {
                        //Token expired
                        if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                        {
                            context.Response.Headers.Add("Token-Expired", "true");
                        }
                        return Task.CompletedTask;
                    }
                };
            });

            //注入授权Handler
            services.AddSingleton<IAuthorizationHandler, PolicyHandler>();
            #endregion

            #region Scrutor
            //scrutor 注册

            // 自动地发现并注册指定的服务
            services.Scan(
                x =>
                {
                    var entryAssembly = Assembly.GetEntryAssembly();
                    var referencedAssemblies = entryAssembly.GetReferencedAssemblies().Select(Assembly.Load);
                    var assemblies = new List<Assembly> { entryAssembly }.Concat(referencedAssemblies);

                    x.FromAssemblies(assemblies)
                             .AddClasses(classes => classes.Where(t => t.Name.EndsWith("Services", StringComparison.OrdinalIgnoreCase)))
                            .AsImplementedInterfaces()
                            .WithScopedLifetime()


                                  .AddClasses(classes => classes.Where(t => t.Name.EndsWith("DBContext", StringComparison.OrdinalIgnoreCase)))
                            .AsImplementedInterfaces()
                            .WithScopedLifetime()

                             .AddClasses(classes => classes.Where(t => t.Name.EndsWith("Repository", StringComparison.OrdinalIgnoreCase)))
                            .AsImplementedInterfaces()
                            .WithScopedLifetime();
                });


            //EF上下文注册
            services.Scan(scan => scan
                 .AddTypes(typeof(EntityFrameworkDbContext))
                         .AsSelf()
                       .WithSingletonLifetime()
                     );

            #endregion

            #region Swagger
            //https://github.com/domaindrivendev/Swashbuckle.AspNetCore
            services.AddSwaggerGen(c =>
            {

                c.SwaggerDoc("v1", new Info { Title = "CROCODIE API", Version = "v1" });
                c.DocInclusionPredicate((docName, description) => true);
                c.AddSecurityDefinition("Bearer", new ApiKeyScheme
                {
                    Description = "Authorization format : Bearer {token}",
                    Name = "Authorization",
                    In = "header",
                    Type = "apiKey"
                });//api界面新增authorize按钮

                //c.SwaggerDoc("v1", new Info
                //{
                //    Version = "v1",
                //    Title = "ToDo API",
                //    Description = "A simple example ASP.NET Core Web API",
                //    TermsOfService = "None",
                //    Contact = new Contact
                //    {
                //        Name = "",
                //        Email = string.Empty,
                //        Url = ""
                //    },
                //    License = new License
                //    {
                //        Name = "",
                //        Url = ""
                //    }
                //});

                //c.DocInclusionPredicate((docName, description) => true);
                //c.AddSecurityDefinition("Bearer", new ApiKeyScheme
                //{
                //    Description = "Authorization format : Bearer {token}",
                //    Name = "Authorization",
                //    In = "header",
                //    Type = "apiKey"
                //});//api界面新增authorize按钮

                var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                c.IncludeXmlComments(xmlPath, true);

                //接入identityserver
                //c.AddSecurityDefinition("oauth2", new OAuth2Scheme
                //{
                //    Flow = "implicit", // 只需通过浏览器获取令牌（适用于swagger）
                //    AuthorizationUrl = "http://localhost:5000/connect/authorize",//获取登录授权接口
                //    Scopes = new Dictionary<string, string> {
                //        { "YSC_OpenPlatform_API", "是否准许YSC_OpenPlatform_API访问" }//指定客户端请求的api作用域。 如果为空，则客户端无法访问
                //    }
                //});
                //c.OperationFilter<AuthResponsesOperationFilter>();
            });
            //_ = services.AddSwaggerGen(options =>
            //{
            //    options.SwaggerDoc("doc", new Swashbuckle.AspNetCore.Swagger.Info() { Title = "@XXX" });
            //    //为了兼容IISExpress，需添加AppDomain.CurrentDomain.BaseDirectory 
            //    options.IncludeXmlComments(AppDomain.CurrentDomain.BaseDirectory + "comment.xml");

            //    //添加文件上传按钮，另外api/action需添加特性[AddSwaggerFileUploadButton]
            //    //如果代码包含services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);那么这些代码就不需要了
            //    //<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="4.5.5" />
            //    //using Microsoft.AspNetCore.Mvc;
            //    //options.OperationFilter<AddFileParamTypesOperationFilter>();
            //});
            #endregion
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }
         
            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();

            _ = app.UseSwagger();
            _ = app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
                c.OAuthClientId("api1_client");
                c.OAuthAppName("api1 描述"); // 描述
            });

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}
